package cn.jasonone.tio.tcp.listener;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.tio.client.intf.ClientAioListener;
import org.tio.core.ChannelContext;
import org.tio.core.intf.AioListener;
import org.tio.core.intf.Packet;
import org.tio.server.intf.ServerAioListener;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 全局监听器
 *
 * @author xujie
 * @version 1.0
 * @date 2022/1/19 8:55
 */
@Slf4j
public class GlobalAioListener implements ServerAioListener, ClientAioListener, InitializingBean, ApplicationContextAware {
    private static final Marker MARKER = MarkerFactory.getMarker("AioListener");
    /**
     * 监听器缓存
     */
    private Set<AioListener> aioListenerCache = new HashSet<>();
    @Setter
    private ApplicationContext applicationContext;

    @Override
    public boolean onHeartbeatTimeout(ChannelContext channelContext, Long interval, int heartbeatTimeoutCount) {
        boolean flag = false;
        for (AioListener listener : aioListenerCache) {
            if (listener instanceof ServerAioListener) {
                try {
                    flag = flag || ((ServerAioListener) listener).onHeartbeatTimeout(channelContext, interval, heartbeatTimeoutCount);
                } catch (Exception e) {
                    log.error(MARKER, "监听器处理失败", e);
                }
            }
        }
        return flag;
    }

    @Override
    public void onAfterConnected(ChannelContext channelContext, boolean isConnected, boolean isReconnect) throws Exception {
        for (AioListener listener : aioListenerCache) {
            try {
                listener.onAfterConnected(channelContext, isConnected, isReconnect);
            } catch (Exception e) {
                log.error(MARKER, "监听器处理失败", e);
            }
        }
    }

    @Override
    public void onAfterDecoded(ChannelContext channelContext, Packet packet, int packetSize) throws Exception {
        for (AioListener listener : aioListenerCache) {
            try {
                listener.onAfterDecoded(channelContext, packet, packetSize);
            } catch (Exception e) {
                log.error(MARKER, "监听器处理失败", e);
            }
        }
    }

    @Override
    public void onAfterReceivedBytes(ChannelContext channelContext, int receivedBytes) throws Exception {
        for (AioListener listener : aioListenerCache) {
            try {
                listener.onAfterReceivedBytes(channelContext, receivedBytes);
            } catch (Exception e) {
                log.error(MARKER, "监听器处理失败", e);
            }
        }
    }

    @Override
    public void onAfterSent(ChannelContext channelContext, Packet packet, boolean isSentSuccess) throws Exception {
        for (AioListener listener : aioListenerCache) {
            try {
                listener.onAfterSent(channelContext, packet, isSentSuccess);
            } catch (Exception e) {
                log.error(MARKER, "监听器处理失败", e);
            }
        }
    }

    @Override
    public void onAfterHandled(ChannelContext channelContext, Packet packet, long cost) throws Exception {
        for (AioListener listener : aioListenerCache) {
            try {
                listener.onAfterHandled(channelContext, packet, cost);
            } catch (Exception e) {
                log.error(MARKER, "监听器处理失败", e);
            }
        }
    }

    @Override
    public void onBeforeClose(ChannelContext channelContext, Throwable throwable, String remark, boolean isRemove) throws Exception {
        for (AioListener listener : aioListenerCache) {
            try {
                listener.onBeforeClose(channelContext, throwable, remark, isRemove);
            } catch (Exception e) {
                log.error(MARKER, "监听器处理失败", e);
            }
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, AioListener> aioListeners = applicationContext.getBeansOfType(AioListener.class);
        for (AioListener listener : aioListeners.values()) {
            if (!(listener instanceof GlobalAioListener) && this.aioListenerCache.add(listener)) {
                log.debug(MARKER, "注册[AioListener]监听器:{}", listener);
            }
        }
    }
}
